/*
 * qWikiOffice Desktop 1.0 Copyright(c) 2007-2008, Integrated Technologies, Inc.
 * licensing@qwikioffice.com
 * 
 * http://www.qwikioffice.com/license
 */

Ext.Desktop = Ext.extend(Ext.util.Observable, {
			/**
			 * @cfg. {Ext.app.App}
			 */
			app : null,
			/**
			 * @cfg {Object} Example: { "fontColor": "FFFFFF", "theme": {"id":
			 *      1,"name": "Blue","file": "resources/css/xtheme-blue.css"},
			 *      "taskbarTransparency": "100" }
			 */
			appearance : null,
			/**
			 * @cfg {Object} Example: { "color": "f9f9f9", "wallpaper": {"id":
			 *      3,"name": "Blue Swirl","file":
			 *      "resources/wallpapers/blue-swirl.jpg"}, "wallpaperPosition":
			 *      "tile" }
			 */
			background : null,
			/**
			 * @cfg {Object} The launchers object. Contains the moduleId's of
			 *      the modules to add to each launcher.
			 */
			launchers : {
				autorun : [],
				quickstart : [],
				shortcut : []
			},
			/**
			 * @cfg {Object} The logout button config.
			 */
			logoutConfig : {
				handler : function() {
					alert("登出系统地址未设置");
				},
				iconCls : 'icon-logout-16',
				text : '登出'
			},
			/**
			 * @cfg {Function} Function that handles sorting of the Start Menu.
			 *      Return true to swap a and b. Examples: function(a, b){ //
			 *      Sort in ASC alphabetical order if( b.text < a.text ){ return
			 *      true; } return false; } function(a, b){ // Sort in ASC
			 *      alphabetical order with menus at the bottom if( (b.text <
			 *      a.text) && !b.menu ){ return true; } return false; }
			 */
			startMenuSortFn : function(a, b) { // Sort in ASC alphabetical
				if (b < a) {
					// if (((b.menu && a.menu) && (b.sequence < a.sequence)) ||
					// (b.sequence && !a.sequence) || ((b.sequence < a.sequence)
					// && !a.sequence)) {
					return true;
				}
				return false;
			},
			/**
			 * Read only.
			 * 
			 * @type {Ext.Window}
			 */
			activeWindow : null,
			/**
			 * Read only.
			 * 
			 * @type {Ext.menu.Menu}
			 */
			contextMenu : null,
			/**
			 * Read only.
			 * 
			 * @type {Ext.ux.Shortcuts}
			 */
			shortcuts : null,
			/**
			 * Read only.
			 * 
			 * @type {Ext.ux.Taskbar}
			 */
			taskbar : null,
			/**
			 * Read only.
			 * 
			 * @type {Ext.WindowGroup}
			 */
			windows : new Ext.WindowGroupUec3(),
			maxZIndexwindows : new Ext.WindowGroupUec3({zseed:8000}),
			/**
			 * Read only.
			 * 
			 * @type {Number}
			 */
			xTickSize : 1,
			/**
			 * Read only.
			 * 
			 * @type {Number}
			 */
			yTickSize : 1,

			/**
			 * @param {Object}
			 *            config.
			 */
			constructor : function(config) {
				this.app = config.app;

				this.addEvents({
							winactivate : true,
							winbeforeclose : true,
							windeactivate : true
						});

				if (config.appearance) {
					this.appearance = config.appearance;
				}
				if (config.background) {
					this.background = config.background;
				}
				if (config.launchers) {
					Ext.apply(this.launchers, config.launchers);
				}
				if (config.logoutConfig) {
					this.logoutConfig = config.logoutConfig;
				}
				if (config.startMenuSortFn) {
					this.startMenuSortFn = config.startMenuSortFn;
				}

				var taskbarConfig = config.taskbarConfig || {};
				if (taskbarConfig.position === 'top') {
					this.taskbar = new Ext.ux.TaskBar(taskbarConfig);
					this.el = Ext.getBody().createChild({
								tag : 'div',
								cls : 'x-desktop'
							});
				} else {
					this.el = Ext.getBody().createChild({
								tag : 'div',
								cls : 'x-desktop'
							});
					this.taskbar = new Ext.ux.TaskBar(taskbarConfig);
				}
				this.taskbar.desktop = this;

				this.contextMenu = new Ext.menu.Menu({
							items : [{
										text : '关闭所有窗口',
										handler : this.closeWindows,
										scope : this
									}, '-', {
										text : '最小化所有窗口',
										handler : this.minimizeWindows,
										scope : this
									}, '-', {
										text : '重置',
										handler : this.tileWindows,
										scope : this
									}, {
										text : '层叠',
										handler : this.cascadeWindows,
										scope : this
									}, {
										text : '分割窗口',
										handler : this.checkerboardWindows,
										scope : this
									}, {
										text : '水平平铺',
										handler : this.snapFitWindows,
										scope : this
									}, {
										text : '垂直平铺',
										handler : this.snapFitVWindows,
										scope : this
									}]
						});

				this.shortcuts = new Ext.ux.Shortcuts(this);

				// todo: fix bug where Ext.Msg are not displayed properly
				this.windows.zseed = 7000; // 10000;

				Ext.Desktop.superclass.constructor.call(this);

				this.initEvents();
				this.initAppearance();
				this.initBackground();
				this.initModules();
				this.initLaunchers();
				this.initLogout();
				this.layout();
			},

			initEvents : function() {
				Ext.EventManager.onWindowResize(this.layout, this);

				this.el.on('contextmenu', function(e) {
							if (e.target.id === this.el.id) {
								e.stopEvent();
								if (!this.contextMenu.el) {
									this.contextMenu.render();
								}
								this.contextMenu.showAt(e.getXY());
							}
						}, this);
			},

			initModules : function() {
				var ms = this.app.modules;
				if (!ms) {
					return false;
				}

				for (var i = 0, len = ms.length; i < len; i++) {
					if (ms[i].launcher) {
						ms[i].launcher.handler = this.launchWindow.createDelegate(this, [ms[i].id]);
					}
					ms[i].loaded = false;

				}

				return true;
			},

			initLaunchers : function() {
				this.initStartMenu();
				this.initContextMenu();
				this.initQuickStart();
				this.initShortcut();
				this.initAutoRun();
			},

			initStartMenu : function() {
				var menu = this.taskbar.startButton.menu;
				var config = this.buildStartItemConfig() || {};
				if (config.items) {
					menu.add(config.items);
				}
				if (config.toolItems) {
					menu.addTool.apply(menu, config.toolItems);
				}
				menu.setHeight(280);
			},

			initAutoRun : function() {
				var mIds = this.launchers.autorun;
				if (mIds && mIds.length > 0) {
					this.app.onReady(function() {
								for (var i = 0, len = mIds.length; i < len; i++) {
									var m = this.app.getModule(mIds[i]);
									if (m) {
										m.autorun = true;
										this.launchWindow(mIds[i]);
									}
								}
							}, this);
				}
			},

			initShortcut : function() {
				var mIds = this.launchers.shortcut;
				if (mIds) {
					for (var i = 0, len = mIds.length; i < len; i++) {
						this.addShortcut(mIds[i], false);
					}
				}
			},

			initQuickStart : function() {
				var mIds = this.launchers.quickstart;
				if (mIds) {
					for (var i = 0, len = mIds.length; i < len; i++) {
						this.addQuickStartButton(mIds[i], false);
					}
				}
			},

			initContextMenu : function() {
				var ms = this.app.modules;
				if (ms) {
					for (var i = 0, len = ms.length; i < len; i++) {
						if (ms[i].launcherPaths && ms[i].launcherPaths.contextmenu) {
							this.addContextMenuItem(ms[i].id);
						}
					}
				}
			},

			initLogout : function() {
				if (this.logoutConfig) {
					this.taskbar.startButton.menu.addTool(this.logoutConfig);
				}
			},

			/**
			 * Provides the handler to the module launcher. Requests the module,
			 * which will load the module if needed. Passes in the callback and
			 * scope as params.
			 * 
			 * @param {string}
			 *            id
			 */
			launchWindow : function(id) {
				var m = this.app.requestModule(id, function(m) {
							if (m) {
								var params = {
									"desktopModule" : m
								};
								m.createWindow(params);
							}
						}, this);
			},
			launchWindowByParam : function(id, params) {
				var m = this.app.requestModule(id, function(m) {
							if (m) {
								if (params) {
									params["desktopModule"] = m;
								} else {
									params = {
										"desktopModule" : m
									};
								}
								m.createWindow(params);
							}
						}, this);
			},
			/**
			 * @param {object}
			 *            config The window config object.
			 * @param {string}
			 *            cls The class to use instead of Ext.Window.
			 */
			createWindow : function(config, cls) {
				var win = new (cls || Ext.Window)(Ext.applyIf(config || {}, {
							manager : this.windows,
							minimizable : true,
							maximizable : true,
							shadow : 'frame'
						}));

				win.render(this.el);
				var curModule = null;
				var markTask = true;
				var len = arguments.callee.caller.arguments.length;
				if (len > 0) {
					var params = arguments.callee.caller.arguments[len - 1];
					if (Ext.isObject(params) && params.desktopModule) {
						curModule = params.desktopModule;
						curModule.curWindow = win;
						if (false == params.markTask) {
							markTask = false;
						}
					}
				}
				if (markTask && (curModule == null || curModule.markTask)) {
					win.taskButton = this.taskbar.addTaskButton(win);
					win.animateTarget = win.taskButton.el;
				}
				win.on({
							'activate' : {
								fn : function(win) {
									this.markActive(win);
									this.fireEvent('winactivate', this, win);
								},
								scope : this
							},
							'beforeclose' : {
								fn : function(win) {
									this.fireEvent('winbeforeclose', this, win);
								},
								scope : this
							},
							'beforeshow' : {
								fn : this.markActive,
								scope : this
							},
							'deactivate' : {
								fn : function(win) {
									this.markInactive(win);
									this.fireEvent('windeactivate', this, win);
								},
								scope : this
							},
							'minimize' : {
								fn : this.minimizeWin,
								scope : this
							},
							'close' : {
								fn : this.removeWin,
								scope : this
							}
						});

				this.layout();
				return win;
			},
			/**
			 * 不会出现在任务栏上
			 *                     
			 */
			createWindowNoTask : function(config, cls) {
				var win = new (cls || Ext.Window)(Ext.applyIf(config || {}, {
							manager : this.windows,
							minimizable : true,
							maximizable : true,
							shadow : 'frame'
						}));

				win.render(this.el);
				win.on({
							'activate' : {
								fn : function(win) {
									this.markActive(win);
									this.fireEvent('winactivate', this, win);
								},
								scope : this
							},
							'beforeclose' : {
								fn : function(win) {
									this.fireEvent('winbeforeclose', this, win);
								},
								scope : this
							},
							'beforeshow' : {
								fn : this.markActive,
								scope : this
							},
							'deactivate' : {
								fn : function(win) {
									this.markInactive(win);
									this.fireEvent('windeactivate', this, win);
								},
								scope : this
							},
							'minimize' : {
								fn : this.minimizeWin,
								scope : this
							},
							'close' : {
								fn : this.removeWin,
								scope : this
							}
						});

				this.layout();
				return win;
			},
			createWindowNoTaskMaxZIndex : function(config, cls) {
				var win = new (cls || Ext.Window)(Ext.applyIf(config || {}, {
							manager : this.maxZIndexwindows,
							minimizable : true,
							maximizable : true,
							shadow : 'frame'
						}));

				win.render(this.el);
				win.on({
							'activate' : {
								fn : function(win) {
									this.markActive(win);
									this.fireEvent('winactivate', this, win);
								},
								scope : this
							},
							'beforeclose' : {
								fn : function(win) {
									this.fireEvent('winbeforeclose', this, win);
								},
								scope : this
							},
							'beforeshow' : {
								fn : this.markActive,
								scope : this
							},
							'deactivate' : {
								fn : function(win) {
									this.markInactive(win);
									this.fireEvent('windeactivate', this, win);
								},
								scope : this
							},
							'minimize' : {
								fn : this.minimizeWin,
								scope : this
							},
							'close' : {
								fn : this.removeWin,
								scope : this
							}
						});

				this.layout();
				return win;
			},
			/**
			 * @param {Ext.Window}
			 *            win The window to minimize.
			 */
			minimizeWin : function(win) {
				win.minimized = true;
				if (win.taskButton) {
					win.hide();
				} else {
					win.close();
				}
			},

			/**
			 * @param {Ext.Window}
			 *            win The window to mark active.
			 */
			markActive : function(win) {
				if (this.activeWindow && this.activeWindow != win) {
					this.markInactive(this.activeWindow);
				}
				if (win.taskButton) {
					this.taskbar.setActiveButton(win.taskButton);

					Ext.fly(win.taskButton.el).addClass('active-win');
				}
				this.activeWindow = win;
				win.minimized = false;
			},

			/**
			 * @param {Ext.Window}
			 *            win The window to mark inactive.
			 */
			markInactive : function(win) {
				if (win == this.activeWindow) {
					this.activeWindow = null;
					if (win.taskButton) {
						Ext.fly(win.taskButton.el).removeClass('active-win');
					}
				}
			},

			/**
			 * @param {Ext.Window}
			 *            win The window to remove.
			 */
			removeWin : function(win) {
				if (win.taskButton) {
					this.taskbar.removeTaskButton(win.taskButton);
				}
				this.layout();
			},

			layout : function() {
				this.el.setHeight(Ext.lib.Dom.getViewHeight() - this.getTaskbarHeight());
			},

			getManager : function() {
				return this.windows;
			},

			/**
			 * @param {string}
			 *            id The window id.
			 */
			getWindow : function(id) {
				return this.windows.get(id);
			},
			/**
			 * @param {string}
			 *            uecId The window uecId.
			 */
			getWindowByUecId : function(uecId) {
				return this.windows.getUecId(uecId);
			},
			/**
			 * @param {string}
			 *            uecId The window uecId.
			 */
			changeWindowUecId : function(oldUecId, newUecId) {
				return this.windows.updateUecId(oldUecId, newUecId);
			},

			/**
			 * @param {String}
			 *            key The launcher key. Options are: 'autorun',
			 *            'quickstart' and 'shortcut'.
			 */
			getLauncher : function(key) {
				return this.launchers[key];
			},

			/**
			 * @param {String}
			 *            key The launcher key. Options are: 'autorun',
			 *            'quickstart' and 'shortcut'.
			 * @param {String}
			 *            id The module id to add.
			 */
			addToLauncher : function(key, id) {
				var c = this.getLauncher(key);
				if (c) {
					c.push(id);
				}
			},

			/**
			 * @param {String}
			 *            key The launcher key. Options are: 'autorun',
			 *            'quickstart' and 'shortcut'.
			 * @param {String}
			 *            id The module id to remove.
			 */
			removeFromLauncher : function(key, id) {
				var c = this.getLauncher(key);
				if (c) {
					var i = 0;
					while (i < c.length) {
						if (c[i] == id) {
							c.splice(i, 1);
						} else {
							i++;
						}
					}
				}
			},

			getTaskbarPosition : function() {
				return this.taskbar.position;
			},

			getTaskbarHeight : function() {
				return this.taskbar.isVisible() ? this.taskbar.getHeight() : 0;
			},

			getViewHeight : function() {
				return (Ext.lib.Dom.getViewHeight() - this.getTaskbarHeight());
			},

			getViewWidth : function() {
				return Ext.lib.Dom.getViewWidth();
			},

			getWinWidth : function() {
				var width = this.getViewWidth();
				return width < 200 ? 200 : width;
			},

			getWinHeight : function() {
				var height = this.getViewHeight();
				return height < 100 ? 100 : height;
			},

			/**
			 * @param {integer}
			 *            width The width.
			 */
			getWinX : function(width) {
				return (Ext.lib.Dom.getViewWidth() - width) / 2
			},

			/**
			 * @param {integer}
			 *            height The height.
			 */
			getWinY : function(height) {
				return (Ext.lib.Dom.getViewHeight() - this.getTaskbarHeight() - height) / 2;
			},

			setTickSize : function(xTickSize, yTickSize) {
				this.xTickSize = xTickSize;
				if (arguments.length == 1) {
					this.yTickSize = xTickSize;
				} else {
					this.yTickSize = yTickSize;
				}
				this.windows.each(function(win) {
							win.dd.xTickSize = this.xTickSize;
							win.dd.yTickSize = this.yTickSize;
							win.resizer.widthIncrement = this.xTickSize;
							win.resizer.heightIncrement = this.yTickSize;
						}, this);
			},

			cascadeWindows : function() {
				var x = 0, y = 0;
				this.windows.each(function(win) {
							if (win.isVisible() && !win.maximized) {
								win.setPosition(x, y);
								win.toFront();
								x += 20;
								y += 20;
							}
						}, this);
			},

			tileWindows : function() {
				var availWidth = this.el.getWidth(true);
				var x = this.xTickSize;
				var y = this.yTickSize;
				var nextY = y;
				this.windows.each(function(win) {
							if (win.isVisible() && !win.maximized) {
								var w = win.el.getWidth();
								// Wrap to next row if we are not at the line
								// start and this Window will go off the end
								if ((x > this.xTickSize) && (x + w > availWidth)) {
									x = this.xTickSize;
									y = nextY;
								}

								win.setPosition(x, y);
								x += w + this.xTickSize;
								nextY = Math.max(nextY, y + win.el.getHeight() + this.yTickSize);
							}
						}, this);
			},

			closeWindows : function() {
				this.windows.each(function(win) {
							win.close();
						}, this);
			},

			minimizeWindows : function() {
				this.windows.each(function(win) {
							this.minimizeWin(win);
						}, this);
			},

			checkerboardWindows : function() {
				var availWidth = this.el.getWidth(true);
				var availHeight = this.el.getHeight(true);

				var x = 0, y = 0;
				var lastx = 0, lasty = 0;

				// square size should be a value set user?
				var square = 400;

				this.windows.each(function(win) {
							// if (win.isVisible() && !win.maximized) {
							if (win.isVisible()) {
								// Subtract padding, should be a value set user?
								win.setWidth(square - 10);
								win.setHeight(square - 10);

								win.setPosition(x, y);
								x += square;

								if (x + square > availWidth) {
									x = lastx;
									y += square;

									if (y > availHeight) {
										lastx += 20;
										lasty += 20;
										x = lastx;
										y = lasty;
									}
								}
							}
						}, this);
			},

			snapFitWindows : function() {
				var availWidth = this.el.getWidth(true);
				var availHeight = this.el.getHeight(true);

				var x = 0, y = 0;

				// How to get number of windows?
				// var snapCount = windows.length;
				var snapCount = 0;

				this.windows.each(function(win) {
							if (win.isVisible()) {
								snapCount++;
							}
						}, this);
				// above loop seems unnecessary?

				var snapSize = parseInt(availWidth / snapCount);

				if (snapSize > 0) {
					this.windows.each(function(win) {
								if (win.isVisible()) {
									// Subtract 10 for padding?
									win.setWidth(snapSize);
									win.setHeight(availHeight);

									win.setPosition(x, y);
									x += snapSize;
								}
							}, this);
				}
			},

			snapFitVWindows : function() {
				var availWidth = this.el.getWidth(true);
				var availHeight = this.el.getHeight(true);

				var x = 0, y = 0;

				// How to get number of windows?
				// var snapCount = windows.length;
				var snapCount = 0;

				this.windows.each(function(win) {
							if (win.isVisible()) {
								snapCount++;
							}
						}, this);
				// above loop seems unnecessary?

				var snapSize = parseInt(availHeight / snapCount);

				if (snapSize > 0) {
					this.windows.each(function(win) {
								if (win.isVisible()) {
									// Subtract 10 for padding?
									win.setWidth(availWidth);
									win.setHeight(snapSize);

									win.setPosition(x, y);
									y += snapSize;
								}
							}, this);
				}
			},

			initAppearance : function() {
				var a = this.appearance;
				if (a) {
					this.setFontColor(a.fontColor);
					this.setTheme(a.theme);
					this.setTaskbarTransparency(a.taskbarTransparency);
				}
			},

			getAppearance : function() {
				return this.appearance;
			},

			initBackground : function() {
				var b = this.background;
				if (b) {
					this.setBackgroundColor(b.color);
					this.setWallpaperPosition(b.wallpaperPosition);
					this.setWallpaper(b.wallpaper);
				}
			},

			getBackground : function() {
				return this.background;
			},

			/**
			 * @param {string}
			 *            hex The hexidecimal number for the color.
			 */
			setBackgroundColor : function(hex) {
				if (hex) {
					Ext.getBody().setStyle('background-color', '#' + hex);
					this.background.backgroundcolor = hex;
				}
			},

			/**
			 * @param {string}
			 *            hex The hexidecimal number for the color.
			 */
			setFontColor : function(hex) {
				if (hex) {
					// Ext.util.CSS.updateRule('.ux-shortcut-btn-text', 'color',
					// '#'+hex);
					this.shortcuts.setFontColor(hex);
					this.appearance.fontColor = hex;
				}
			},

			/**
			 * @param {object}
			 *            o The data for the theme. Example: { id: 1, name:
			 *            'Vista Black', file: 'path/to/file' }
			 */
			setTheme : function(o) {
				if (o && o.id && o.name && o.file) {
					Ext.util.CSS.swapStyleSheet('theme', o.file);
					this.appearance.theme = o;
				}
			},

			/**
			 * @param {integer}
			 *            v The value. An integer from 0 to 100.
			 */
			setTaskbarTransparency : function(v) {
				if (v >= 0 && v <= 100) {
					this.taskbar.el.addClass("transparent");
					Ext.util.CSS.updateRule('.transparent', 'opacity', v / 100);
					Ext.util.CSS.updateRule('.transparent', '-moz-opacity', v / 100);
					Ext.util.CSS.updateRule('.transparent', 'filter', 'alpha(opacity=' + v + ')');

					this.appearance.taskbarTransparency = v;
				}
			},

			getWallpaper : function() {
				return this.background.wallpaper;
			},

			/**
			 * @param {object}
			 *            o The data for the wallpaper. Example: { id: 1, name:
			 *            'Blank', file: 'path/to/file' }
			 */
			setWallpaper : function(o) {
				if (o && o.id && o.name && o.file) {

					var notifyWin = this.showNotification({
								html : '系统正在初始化...',
								title : '信息提示'
							});

					var wp = new Image();
					wp.src = o.file;

					var task = new Ext.util.DelayedTask(verify, this);
					task.delay(200);

					this.background.wallpaper = o;
				}

				function verify() {
					if (wp.complete) {
						task.cancel();
						// 取消通知
						notifyWin.setIconClass('x-icon-done');
						notifyWin.setTitle('信息提示');
						notifyWin.setMessage('系统初始化完成.');
						this.hideNotification(notifyWin);

						document.body.background = wp.src;
					} else {
						task.delay(200);
					}
				}
			},

			/**
			 * @param {string}
			 *            pos Options are 'tile' or 'center'.
			 */
			setWallpaperPosition : function(pos) {
				if (pos) {
					var b = Ext.getBody();
					if (pos === "center") {
						b.removeClass('wallpaper-tile');
						b.addClass('wallpaper-center');
					} else if (pos === "tile") {
						b.removeClass('wallpaper-center');
						b.addClass('wallpaper-tile');
					}
					this.background.wallpaperPosition = pos;
				}
			},

			/**
			 * @param {object}
			 *            config The config object.
			 */
			showNotification : function(config) {
				var win = new Ext.ux.Notification(Ext.apply({
							animateTarget : this.taskbar.el,
							animateFrom : this.getTaskbarPosition(),
							autoDestroy : true,
							hideDelay : 5000,
							html : '',
							iconCls : 'x-icon-waiting',
							title : ''
						}, config));
				win.show();

				return win;
			},

			/**
			 * @param {Ext.ux.Notification}
			 *            win The notification window.
			 * @param {integer}
			 *            delay The delay time in milliseconds.
			 */
			hideNotification : function(win, delay) {
				if (win) {
(function			() {
						win.animHide();
					}).defer(delay || 3000);
				}
			},

			/**
			 * @param {string}
			 *            id The id of the module to add.
			 */
			addAutoRun : function(id) {
				var m = this.app.getModule(id);
				var c = this.getLauncher('autorun');

				if (c && m && !m.autorun) {
					m.autorun = true;
					c.push(id);
				}
			},

			/**
			 * @param {string}
			 *            id The id of the module to remove.
			 */
			removeAutoRun : function(id) {
				var m = this.app.getModule(id);
				var c = this.getLauncher('autorun');

				if (c && m && m.autorun) {
					var i = 0;

					while (i < c.length) {
						if (c[i] == id) {
							c.splice(i, 1);
						} else {
							i++;
						}
					}

					m.autorun = null;
				}
			},

			/**
			 * @param {string}
			 *            id The id of the module to add.
			 */
			addContextMenuItem : function(id) {
				var m = this.app.getModule(id);

				if (m && !m.contextMenuItem && m.launcher) {
					var c = m.launcher;

					this.contextMenu.add({
								handler : this.launchWindow.createDelegate(this, [id]),
								iconCls : c.iconCls,
								text : c.text,
								tooltip : c.tooltip || ''
							});
				}
			},

			/**
			 * @param {string}
			 *            id The module id
			 * @param {boolean}
			 *            updateConfig
			 */
			addShortcut : function(id, updateConfig) {
				var m = this.app.getModule(id);

				if (m && !m.shortcut) {
					var c = m.launcher;

					m.shortcut = this.shortcuts.addShortcut({
								handler : this.launchWindow.createDelegate(this, [id]),
								iconCls : c.shortcutIconCls,
								text : c.text,
								tooltip : c.tooltip || ''
							});

					if (updateConfig) {
						this.addToLauncher('shortcut', id);
					}
				}
			},

			/**
			 * @param {string}
			 *            id The module id
			 * @param {boolean}
			 *            updateConfig
			 */
			removeShortcut : function(id, updateConfig) {
				var m = this.app.getModule(id);

				if (m && m.shortcut) {
					this.shortcuts.removeShortcut(m.shortcut);
					m.shortcut = null;

					if (updateConfig) {
						this.removeFromLauncher('shortcut', id);
					}
				}
			},

			/**
			 * @param {string}
			 *            id The module id
			 * @param {boolean}
			 *            updateConfig
			 */
			addQuickStartButton : function(id, updateConfig) {
				var m = this.app.getModule(id);

				if (m && !m.quickStartButton) {
					var c = m.launcher;

					m.quickStartButton = this.taskbar.addQuickStartButton({
								handler : this.launchWindow.createDelegate(this, [id]),
								iconCls : c.iconCls,
								scope : c.scope,
								text : c.text,
								tooltip : c.tooltip || c.text
							});

					if (updateConfig) {
						this.addToLauncher('quickstart', id);
					}
				}
			},

			/**
			 * @param {string}
			 *            id The module id
			 * @param {boolean}
			 *            updateConfig
			 */
			removeQuickStartButton : function(id, updateConfig) {
				var m = this.app.getModule(id);

				if (m && m.quickStartButton) {
					this.taskbar.removeQuickStartButton(m.quickStartButton);
					m.quickStartButton = null;

					if (updateConfig) {
						this.removeFromLauncher('quickstart', id);
					}
				}
			},

			// private
			addModuleMenu : function(root, menuItem, menuInfo) {

				if (menuInfo) {
					//menuItem.sequence = menuInfo.sequence;
					if (menuInfo.parentId && menuInfo.parentId != 0) {
						// 找到上级菜单信息
						// alert(menuInfo.parentId);
						// var prop=""+menuInfo.parentId;
						var pMenuInfo = this.app.menus["" + menuInfo.parentId];
						if (pMenuInfo) {
							// 判断上级菜单条目是否创建
							if (pMenuInfo.menuItem) {
								this.addModuleMenuItem(pMenuInfo.menuItem.menu, menuItem, menuInfo);
							} else {
								pMenuInfo.menuItem = {
									iconCls : 'ux-start-menu-submenu',
									handler : function() {
										return false;
									},
									menu : {
										items : [menuItem],
										sequences: [menuInfo.sequence]
									},
									text : pMenuInfo.menuName
								};
								this.addModuleMenu(root, pMenuInfo.menuItem, pMenuInfo);
							}
						}
					} else {
						this.addModuleMenuItem(root.menu, menuItem, menuInfo);
					}
				}
			},

			// private
			addModuleMenuItem : function(menu, menuItem, menuInfo) {
				var len=menu.items.length;
				menu.items[len] = menuItem;
				menu.sequences[len] = menuInfo.sequence;
				if (len <= 0) {
					return menu;
				}
				for (var i = len; i > 0; i--) {
					//判断是否需要交换位置
					if (this.startMenuSortFn(menu.sequences[i - 1], menu.sequences[i])) {
						var tempValue = menu.items[i];
						var tempSequence = menu.sequences[i];
						menu.items[i] = menu.items[i - 1];
						menu.items[i - 1] = tempValue;
						menu.sequences[i] = menu.sequences[i - 1];
						menu.sequences[i - 1] = tempSequence;
					}
					//不需要交换时跳出循环
					else
					{
						break;
					}
				}
				return menu;
			},

			/**
			 * Returns the Start Menu items and toolItems configs
			 */
			buildStartItemConfig : function() {
				var ms = this.app.modules;
				var menus = this.app.menus;
				var sortFn = this.startMenuSortFn;

				if (ms && menus) {
					var launcherPaths;
					var paths;
					var sm = {
						menu : {
							items : [],
							sequences: []
						}
					}; // Start Menu
					var smi = sm.menu.items;

					smi.push({
								text : 'startmenu',
								menu : {
									items : [],
									sequences: []
								}
							});
					smi.push({
								text : 'startmenutool',
								menu : {
									items : [],
									sequences: []
								}
							});

					for (var i = 0, iLen = ms.length; i < iLen; i++) {
						var menuIds = ms[i].menuIds;
						if (menuIds) {
							for (var j = 0, jLen = menuIds.length; j < jLen; j++) {
								var menuInfo = menus["" + menuIds[j]];
								this.addModuleMenu(smi[menuInfo.menuGroup], ms[i].launcher, menuInfo);
							}
						}
					}

					return {
						items : smi[0].menu.items,
						toolItems : smi[1].menu.items
					};
				}

				return null;
			}
		});